package com.file.system.plugin.myisam;

import cn.hutool.core.util.ReflectUtil;
import com.file.system.tools.Formater;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.Properties;

import static com.file.system.plugin.shiro.ShiroTools.getId;
import static com.file.system.plugin.shiro.ShiroTools.getName;


@Component
@Intercepts({
        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
public class MyISAMAspect implements Interceptor {
    private static final String insertMethod = "save";
    private static final String updateMethod = "updateById";
    private static final String deleteMethod = "removeById";

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 获取调用时的参数
        Object[] args = invocation.getArgs();
        // 如果参数为空或者参数长度小于2，则直接返回调用结果
        if (args == null || args.length < 2) {
            return invocation.proceed();
        }

        // 获取映射语句
        MappedStatement ms = (MappedStatement) args[0];
        // 获取参数
        Object obj = args[1];
        // 如果映射语句或者参数为空，则直接返回调用结果
        if (ms == null || obj == null) {
            return invocation.proceed();
        }

        // 获取参数的类名
        String clazz = obj.getClass().toString();
        // 如果参数的类名不包含com.file.system.entity，则直接返回调用结果
        if (!clazz.contains("com.file.system.entity")) {
            return invocation.proceed();
        }

        // 获取映射语句的id，并转换为大写
        String methodId = ms.getId().toUpperCase();
        // 如果id以insertMethod开头，则设置insertMethod
        if (methodId.endsWith(insertMethod.toUpperCase())) {
            setInsertMethod(obj);
        // 如果id以updateMethod开头，则设置updateByIdMethod
        } else if (methodId.endsWith(updateMethod.toUpperCase())) {
            setUpdateByIdMethod(obj);
        // 如果id以deleteMethod开头，则设置deleteByIdMethod
        } else if (methodId.endsWith(deleteMethod.toUpperCase())) {
            setDeleteByIdMethod(obj);
        }

        // 返回调用结果
        return invocation.proceed();
    }

    //deleteById
    private void setDeleteByIdMethod(Object obj) {
        //获取对象的类
        Class<?> clazz = obj.getClass();
        //判断类中是否有deleteTime字段
        if (ReflectUtil.hasField(clazz, "deleteTime")) {
            //设置deleteTime字段的值为当前时间
            ReflectUtil.setFieldValue(obj, "deleteTime", LocalDateTime.now());
        }
        //判断类中是否有deleteBy字段
        if (ReflectUtil.hasField(clazz, "deleteBy")) {
            //设置deleteBy字段的值为当前id
            ReflectUtil.setFieldValue(obj, "deleteBy", getId());
        }
        //判断类中是否有deleteName字段
        if (ReflectUtil.hasField(clazz, "deleteName")) {
            //设置deleteName字段的值为当前name
            ReflectUtil.setFieldValue(obj, "deleteName", getName());
        }
    }

    //updateById
    private void setUpdateByIdMethod(Object obj) {
        //获取对象的类
        Class<?> clazz = obj.getClass();
        //判断类中是否有updateTime字段
        if (ReflectUtil.hasField(clazz, "updateTime")) {
            //设置updateTime字段的值为当前时间
            ReflectUtil.setFieldValue(obj, "updateTime", LocalDateTime.now());
        }
        //判断类中是否有updateBy字段
        if (ReflectUtil.hasField(clazz, "updateBy")) {
            //设置updateBy字段的值为当前id
            ReflectUtil.setFieldValue(obj, "updateBy", getId());
        }
        //判断类中是否有updateName字段
        if (ReflectUtil.hasField(clazz, "updateName")) {
            //设置updateName字段的值为当前name
            ReflectUtil.setFieldValue(obj, "updateName", getName());
        }
    }

    //insert
    private void setInsertMethod(Object obj) {
        //获取对象的类
        Class<?> clazz = obj.getClass();
        //如果类中有createTime字段
        if (ReflectUtil.hasField(clazz, "createTime")) {
            //设置createTime字段的值为当前时间
            ReflectUtil.setFieldValue(obj, "createTime", LocalDateTime.now());
        }
        //如果类中有createBy字段
        if (ReflectUtil.hasField(clazz, "createBy")) {
            //设置createBy字段的值为当前id
            ReflectUtil.setFieldValue(obj, "createBy", getId());
        }
        //如果类中有createName字段
        if (ReflectUtil.hasField(clazz, "createName")) {
            //设置createName字段的值为当前name
            ReflectUtil.setFieldValue(obj, "createName", getName());
        }
        //如果类中有isDel字段且isDel字段的值为null
        if (ReflectUtil.hasField(clazz, "isDel") && ReflectUtil.getFieldValue(obj, "isDel") == null) {
            //设置isDel字段的值为0
            ReflectUtil.setFieldValue(obj, "isDel", 0);
        }

        //获取MyISAM注解
        MyISAM myISAM = clazz.getAnnotation(MyISAM.class);
        //如果MyISAM注解不为空
        if (myISAM != null) {
            //将对象转换为Map
            Map<String, String> entity = Formater.objectToMap(obj);
            //获取MyISAM注解的值
            int val = clazz.getAnnotation(MyISAM.class).value();
            //获取id的值
            Long id = Long.valueOf(entity.get("id"));

            //如果类中有tableNum字段
            if (ReflectUtil.hasField(clazz, "tableNum")) {
                //设置tableNum字段的值为id除以MyISAM注解的值取余数
                ReflectUtil.setFieldValue(obj, "tableNum", id % val);
            }
        }
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {

    }
}
